//
//  RichTextWebView.swift
//  JJToolSwift
//
//  Created by heihei on 2024/5/19.
//

import UIKit
@preconcurrency import WebKit

/// 加载富文本注入文本
public let RichTextWebViewHtmlStr = String("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'><style>*{ width: 100%%; margin: 0; padding: 0; box-sizing: border-box;} img{ width: 100%%; height: auto;} video{ width: 100%%; height: auto;}</style></head><body>%@</body></html>")

/// 加载富文本图片宽度自适应注入文本
public let RichTextWebViewAutoHtmlStr = String("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'><style>*{ width: 100%%; margin: 0; padding: 0; box-sizing: border-box;} img{ width: auto; height: auto;} video{ width: 100%%; height: auto;}</style></head><body>%@</body></html>")


/// 加载背景色透明富文本注入文本
public let RichTextWebViewHtmlClearColorStr = String("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'><style>*{ width: 100%%; margin: 0; padding: 0; box-sizing: border-box; font-size: 16px; /* 设置字体大小 */ color: #FFFFFF; /* 设置字体颜色 */ overflow:hidden; background-color:rgba(0,0,0,0); } img{ width: 100%%; height: auto;} video{ width: 100%%; height: auto;}</style></head><body><p>%@</p></body></html>")

open class RichTextWebView: UIView {

    // MARK: - 属性
    /// 外部传入参数
    public var jsParameter :[String:Any]?
    
    /// 事件
    fileprivate var target: AnyObject?
    
    /// 三方登录
    public var isThreeLogin: Bool = false
    
    /// 创建webveiew
    public var webView = WKWebView()
    
    /// 进度条
    fileprivate var progressView = UIProgressView()
    
    /// 创建一个webiview的配置项
    fileprivate let configuretion = WKWebViewConfiguration()
    
    /// 执行JS 需要实现代理方法
    fileprivate var POSTJavaScript = String()
    
    /// 是否是第一次加载
    fileprivate var needLoadJSPOST:Bool?
    
    /// 保存请求链接
    fileprivate var snapShotsArray:Array<Any>?
    
    /// WebView配置项
    public  var webConfig : WkwebViewConfig?
    /// 设置代理
    public var delegate : WKWebViewDelegate?
        
    // MARK: - 初始化
    override public init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    var webViewContentSizeObserver: Any?
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        
    }
    
    /// 封装html 字符串
    /// - Parameter html: html文本
    /// - Returns: html 字符串
    open func getHtmlStr(html:String) -> String{
        
        //注入html
        var htmlStr = RichTextWebViewHtmlStr
        
        //注入html 背景色透明
        if(self.webConfig?.isBackgroundClear == true){
            htmlStr = RichTextWebViewHtmlClearColorStr
        }
        
        let replaceHtml = html.replacingOccurrences(of: "white-space: pre", with: "white-space: normal;word-wrap: break-word;")
        
        let valueStr = String(format:htmlStr, arguments: [replaceHtml])
        return valueStr
    }
    
    // MARK: - 加载UI
    fileprivate func setupUI(webConfig:WkwebViewConfig)  {
        
        // Webview的偏好设置
        configuretion.preferences = WKPreferences()
        configuretion.preferences.minimumFontSize = webConfig.minFontSize
        configuretion.preferences.javaScriptCanOpenWindowsAutomatically = webConfig.isAutomaticallyJavaScript
        
        if #available(iOS 13.0, *) {
            let preferences = WKWebpagePreferences()
            if #available(iOS 14.0, *) {
                preferences.allowsContentJavaScript = true
            } else {
                // Fallback on earlier versions
            }
            configuretion.defaultWebpagePreferences = preferences
        } else {
            // Fallback on earlier versions
        }
        configuretion.userContentController = WKUserContentController()
        //注入交互方法
        _ = webConfig.scriptMessageHandlerArray.map{
            configuretion.userContentController.add(self, name: $0)
        }
        
        //        //注入token
        //        injectTokenData()
        
        webView = WKWebView(frame:frame,configuration: configuretion)
        //开启手势交互
        webView.allowsBackForwardNavigationGestures = webConfig.isAllowsBackForwardGestures
        
        //滚动条
        webView.scrollView.showsVerticalScrollIndicator = webConfig.isShowScrollIndicator
        webView.scrollView.showsHorizontalScrollIndicator = webConfig.isShowScrollIndicator
        
        // 监听支持KVO的属性
        webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
        //内容自适应
        webView.sizeToFit()
        webView.scrollView.delegate = self
        // 禁止水平滑动，保留垂直滑动
        webView.scrollView.isScrollEnabled = true
        webView.scrollView.alwaysBounceHorizontal = false
        
        //是否透明背景
        if(webConfig.isBackgroundClear){
            backgroundColor = UIColor.clear
            webView.backgroundColor = UIColor.clear
            webView.scrollView.backgroundColor = UIColor.clear
            webView.isOpaque = false
        } else {
            backgroundColor = .white
        }
        
        
        //拦截滚动
        if(webConfig.isScrollEnabled){
            webView.scrollView.isScrollEnabled = false;
            webView.scrollView.panGestureRecognizer.isEnabled = false;
            webView.scrollView.bounces = false;
        }
        
        self.addSubview(webView)
        webView.snp.makeConstraints { make in
            make.top.left.right.bottom.equalToSuperview().offset(0)
        }
        
        progressView = UIProgressView(progressViewStyle: .default)
        progressView.frame = CGRect(x: 0, y: 0, width:UIDevice.width, height: webConfig.progressHeight)
        progressView.trackTintColor = webConfig.progressTrackTintColor
        progressView.progressTintColor = webConfig.progressTintColor
        webView.addSubview(progressView)
        progressView.isHidden = webConfig.isProgressHidden
        
        webView.navigationDelegate = self
        webView.uiDelegate = self
        
    }
    
    // MARK: - 加载webView
    /// 加载webView
    public func webloadType(_ target:AnyObject,_ loadType:WkwebLoadType) {
        self.target = target
        setupUI(webConfig:webConfig ?? WkwebViewConfig())
        switch loadType {
            
        //加载普通URL
        case .URLString(let urltring):
            if(urltring.isEmpty){
                return
            }
            
            //服务器连接中会存在中文 需要进行转码
            if let encodedString = urltring.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
                if let url = URL(string:encodedString) {
                    let request = URLRequest(url: url)
                    webView.load(request)
                }
            }
            
        //加载html文件 HTMLName 文件名称
        case .HTMLName(let string):
            loadHost(string: string)
            
        //加载POST请求(url:请求URL，parameters：请求参数)
        case .POST(let string, parameters: let postString):
            needLoadJSPOST = true
            // 给每一个key，value前后加上一个“
            let dictMap = postString.map({"\"\($0.key)\":\"\($0.value)\""})
            POSTJavaScript = "post('\(string)\',{\(dictMap.joined(separator: ","))})"
            loadHost(string: "WKJSPOST")
        
        //加载Html富文本
        case .HTMLContent(content: let content):
            loadHTMLContent(content: content)
        }
    }
    
    
    /// 打开本地html
    /// - Parameter string: 文本地址
    fileprivate func loadHost(string:String) {
        let path = Bundle.main.path(forResource: string, ofType: "html")
        // 获得html内容
        do {
            let html = try String(contentsOfFile: path!, encoding: String.Encoding.utf8)
            // 加载js
            webView.loadHTMLString(html, baseURL: Bundle.main.bundleURL)
        } catch { }
    }
    
    
    /// 加载html文本
    fileprivate func loadHTMLContent(content:String) {
        webView.loadHTMLString(content, baseURL: nil)
    }
    
    /// 执行JavaScript代码
    /// 例如 run_JavaScript(script:"document.getElementById('someElement').innerText")
    ///
    /// Parameter titleStr: title字符串
    public func run_JavaScript(javaScript:String?) {
        if let javaScript = javaScript {
            webView.evaluateJavaScript(javaScript) { result,error in
                self.delegate?.webViewEvaluateJavaScript(result, error: error)
            }
        }
    }
    
    // MARK: - webView 内部事件
    /// 刷新
    public func reload() {
        webView.reload()
    }
    /// 后退
    public func goBack() {
        webView.goBack()
    }
    /// 前进
    public func goForward() {
        webView.goForward()
    }
    /// 遗传webView
    public func removeWebView(){
        webView.removeObserver(self, forKeyPath: "estimatedProgress")
        if let scriptMessage = webConfig?.scriptMessageHandlerArray {
            _ = scriptMessage.map{webView.configuration.userContentController .removeScriptMessageHandler(forName: $0)}
        }
        webView.navigationDelegate = nil
        webView.uiDelegate = nil
        self.removeFromSuperview()
    }
    
    // MARK: - 请求链接处理
    //请求链接处理
    fileprivate func pushCurrentSnapshotView(_ request: NSURLRequest) -> Void {
        // 连接是否为空
        guard let urlStr = snapShotsArray?.last else { return }
        // 转换成URL
        let url = URL(string: urlStr as! String)
        // 转换成NSURLRequest
        let lastRequest = NSURLRequest(url: url!)
        // 如果url是很奇怪的就不push
        if request.url?.absoluteString == "about:blank"{ return }
        // 如果url一样就不进行push
        if (lastRequest.url?.absoluteString == request.url?.absoluteString) {return}
        // snapshotView
        let currentSnapShotView = webView.snapshotView(afterScreenUpdates: true);
        //向数组添加字典
        snapShotsArray = [["request":request,"snapShotView":currentSnapShotView]]
    }
    
    // MARK: - KVO 监听 改变进度条色值 透明度
    //KVO 监听 改变进度条色值 透明度
    open override func observeValue(forKeyPath keyPath: String?,
                                    of object: Any?,
                                    change: [NSKeyValueChangeKey : Any]?,
                                    context: UnsafeMutableRawPointer?) {
        JJLog("observeValue \(String(describing: object)) \(String(describing: change))")
        if keyPath == "estimatedProgress"{
            // 设置进度条透明度
            progressView.alpha = CGFloat(1.0 - webView.estimatedProgress)
            // 给进度条添加进度和动画
            progressView.setProgress(Float(webView.estimatedProgress), animated: true)
            // 结束进度
            if Float(webView.estimatedProgress) >= 1.0{
                progressView.alpha = 0.0
                progressView .setProgress(0.0, animated: false)
            }
            
        }
    }
}

// MARK: - scrollView 滑动代理
extension RichTextWebView:UIScrollViewDelegate {
    /// 监听scrollView 滑动 防止滑动列表中滑动scrollView
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        //拦截滑动
        if((webConfig?.isScrollEnabled) == true) {
            scrollView.contentOffset.y = 0
        }
        
//        //拦截左右滑
//        if scrollView.contentOffset.x != 0 {
//            let point = CGPoint(x: 0, y: scrollView.contentOffset.y)
//            scrollView.setContentOffset(point, animated: false)
//        }
    }
}



// MARK: - WKScriptMessageHandler
extension RichTextWebView: WKScriptMessageHandler{
    //H5js事件回调
    public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if let scriptMessage = webConfig?.scriptMessageHandlerArray {
            self.delegate?.webViewUserContentController(scriptMessage, didReceive: message)
        }
    }
}



// MARK: - WKNavigationDelegate
extension RichTextWebView: WKNavigationDelegate{
    
    //服务器开始请求的时候调用
    public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        
        self.delegate?.webView(webView, decidePolicyFor: navigationAction, decisionHandler: decisionHandler)
        
        let navigationURL = navigationAction.request.url?.absoluteString
        if let requestURL = navigationURL?.removingPercentEncoding {
            //拨打电话
            //兼容安卓的服务器写法:<a class = "mobile" href = "tel://电话号码"></a>
            //或者:<a class = "mobile" href = "tel:电话号码"></a>
            if requestURL.hasPrefix("tel://") {
                if let mobileURL:URL = URL(string: requestURL) {
                    //取消WKWebView 打电话请求
                    decisionHandler(.cancel);
                    //用openURL 这个API打电话
                    UIApplication.shared.open(mobileURL)
                    return
                }
            }
            else if requestURL.hasPrefix("mailto:") {
                // 邮箱
                if let mobileURL:URL = URL(string: requestURL) {
                    decisionHandler(.cancel)
                    UIApplication.shared.open(mobileURL)
                    return
                }
            }
        }
        
        switch navigationAction.navigationType {
        case WKNavigationType.linkActivated:
            pushCurrentSnapshotView(navigationAction.request as NSURLRequest)
            // 富文本 点击超链接，跳转新页面
            if snapShotsArray == nil {
                if let navigationURL = navigationAction.request.url?.absoluteString,
                   navigationURL.hasPrefix("http") {
//                    if let curVC = UIViewController.current() {
//                        let className = String(describing: type(of: curVC))
//                        // 侧边栏单独处理
//                        if className == "HomeSideBarController" {
//                            curVC.dismiss(animated: false) {
//                                pushWKWebVC(url: navigationURL)
//                            }
//                        }
//                        else {
//                            pushWKWebVC(url: navigationURL)
//                        }
//                    } else {
//                        pushWKWebVC(url: navigationURL)
//                    }
                    decisionHandler(.cancel)
                    return
                }
            }
            break
        case WKNavigationType.formSubmitted:
            pushCurrentSnapshotView(navigationAction.request as NSURLRequest)
            break
        case WKNavigationType.backForward:
            break
        case WKNavigationType.reload:
            break
        case WKNavigationType.formResubmitted:
            break
        case WKNavigationType.other:
            pushCurrentSnapshotView(navigationAction.request as NSURLRequest)
            break
        }
        decisionHandler(.allow)
    }
    
    //开始加载
    public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        self.delegate?.webView(webView, didStartProvisionalNavigation: navigation)
    }
    
    //这个是网页加载完成，导航的变化
    public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        
        //页面加载完成的回调
        self.delegate?.webView(webView, didFinish: navigation)
        
        // 判断是否需要加载（仅在第一次加载）
        if needLoadJSPOST == true {
            // 调用使用JS发送POST请求的方法
            run_JavaScript(javaScript: POSTJavaScript)
            // 将Flag置为NO（后面就不需要加载了）
            needLoadJSPOST = false
        }
        
        //获取页面高度
        webView.evaluateJavaScript("document.body.scrollHeight") { (Result, error) in
            if let height = Result as? Double {
                self.delegate?.webViewDocumentHeight(documentHeight:height)
            }
        }
        
        progressView.isHidden = true
        progressView.alpha = 0.0
        progressView .setProgress(0.0, animated: false)
        
        //        // 通过注入 JavaScript 来使 WKWebView 的背景透明
        //        let script = "document.body.style.backgroundColor = 'transparent';"
        //        webView.evaluateJavaScript(script, completionHandler: nil)
        
    }
    
    //跳转失败的时候调用
    public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        self.delegate?.webView(webView, didFail: navigation, withError: error)
        
    }
    // 内容加载失败时候调用
    public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        self.delegate?.webView(webView, didFailProvisionalNavigation: navigation, withError: error)
        progressView.isHidden = true
    }
    
    // 打开新窗口委托
    public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        if navigationAction.targetFrame?.isMainFrame == nil {
            webView.load(navigationAction.request)
        }
        return nil
    }
}


// MARK: - WKUIDelegate 不实现该代理方法 网页内调用弹窗时会抛出异常,导致程序崩溃
extension RichTextWebView: WKUIDelegate{
    
    // 获取js 里面的提示
    public func webView(_ webView: WKWebView,
                        runJavaScriptAlertPanelWithMessage message: String,
                        initiatedByFrame frame: WKFrameInfo,
                        completionHandler: @escaping () -> Void) {

        let alert = UIAlertController(title: "消息", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
            completionHandler()
        }))
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in
            completionHandler()
        }))
        target?.present(alert, animated: true, completion: nil)
    }
    
    // js 信息的交流
    public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        let alert = UIAlertController(title: "消息", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
            completionHandler(true)
        }))
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in
            completionHandler(false)
        }))
        target?.present(alert, animated: true, completion: nil)
    }
    
    // 交互。可输入的文本。
    public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        let alert = UIAlertController(title: prompt, message: defaultText, preferredStyle: .alert)
        
        alert.addTextField { (textField: UITextField) -> Void in
            textField.textColor = UIColor.red
        }
        alert.addAction(UIAlertAction(title:"确定", style: .default, handler: { (_) -> Void in
            completionHandler(alert.textFields![0].text!)
        }))
        target?.present(alert, animated: true, completion: nil)
    }
}
